#pragma once
#include <queue>
#include "Mutex.hpp"
#include "Thread.hpp"

namespace BlockQueueMoudle
{
    using namespace ThreadMoudle;
    const int gcap = 10;

    class Blockqueue
    {

    private:
        bool IsFull() { return _cap == _q.size(); }
        bool IsEmpty() { return _q.empty(); }

    public:
        Blockqueue(int cap = gcap)
            : _cap(cap),_p_cond(PTHREAD_COND_INITIALIZER),_c_cond(PTHREAD_COND_INITIALIZER)
        {

        }
        ~Blockqueue()
        {
            pthread_cond_destroy(&_p_cond);
            pthread_cond_destroy(&_c_cond);
        }
        void Pop(int *out)
        {
            LockGuard lockguard(_mutex);

            //循环判断，防止其他消费者在IsEmpty时进入
            while (IsEmpty())
            {
                printf("消费者等待中...\n");
                _cwait_num++;
                pthread_cond_wait(&_c_cond, _mutex.Mutex_ptr());
                _cwait_num--;
            }

            *out = _q.front();
            _q.pop();
            printf("Pop:%d\n", *out);

            //如果有生产者在等待，唤醒
            if(_pwait_num)
            pthread_cond_signal(&_p_cond);
        }

        void Enqueue(int &in)
        {
            LockGuard lockguard(_mutex);
            while (IsFull())
            {
                _pwait_num++;
                pthread_cond_wait(&_p_cond, _mutex.Mutex_ptr());
                _pwait_num--;

            }

            _q.push(in);
            printf("Equeue: %d\n", in);

            //如果有消费者在等待，唤醒
            if(_cwait_num)
            pthread_cond_signal(&_c_cond);
        }

    private:
        int _cap;
        std::queue<int> _q; // 临界资源
        Mutex _mutex;
        pthread_cond_t _p_cond; // 生产者条件
        pthread_cond_t _c_cond; // 消费者条件

        int _cwait_num;
        int _pwait_num;
    };

}